/**
 ******************************************************************************
 * @file           : bsp_dac.c
 * @brief          : DAC Driver Implementation (STM32F4xx)
 ******************************************************************************
 * @attention
 *
 * DAC驱动实现文件
 * 12位分辨率，输出电压范围：0~3.3V
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/DAC/bsp_dac.h"
#include "./BSP/DAC/bsp_dac_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DAC_VREF_MV     3300        /*!< 参考电压3.3V */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static DAC_HandleTypeDef sg_dac_handle;
static volatile uint8_t sg_dac_ch1_initialized = 0;
static volatile uint8_t sg_dac_ch2_initialized = 0;

/* Private function prototypes -----------------------------------------------*/
static void dac_gpio_init(DAC_Channel_e channel);
static uint32_t dac_get_hal_channel(DAC_Channel_e channel);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       DAC GPIO初始化
 *
 * @param[in]   channel DAC通道
 *
 * @retval      无
 *
 * @note        配置DAC输出引脚为模拟输出模式
 */
static void dac_gpio_init(DAC_Channel_e channel)
{
    GPIO_InitTypeDef gpio_init_struct = {0};

    /* STM32F4xx需要配置Mode/Pull/Speed */
    gpio_init_struct.Mode = GPIO_MODE_ANALOG;
    gpio_init_struct.Pull = GPIO_NOPULL;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;

    if (channel == DAC_CH_1)
    {
        DAC_CH1_GPIO_CLK_ENABLE();
        gpio_init_struct.Pin = DAC_CH1_GPIO_PIN;
        HAL_GPIO_Init(DAC_CH1_GPIO_PORT, &gpio_init_struct);
    }
    else if (channel == DAC_CH_2)
    {
        DAC_CH2_GPIO_CLK_ENABLE();
        gpio_init_struct.Pin = DAC_CH2_GPIO_PIN;
        HAL_GPIO_Init(DAC_CH2_GPIO_PORT, &gpio_init_struct);
    }
}

/**
 * @brief       获取HAL库通道定义
 *
 * @param[in]   channel DAC通道枚举
 *
 * @retval      HAL通道定义
 */
static uint32_t dac_get_hal_channel(DAC_Channel_e channel)
{
    return (channel == DAC_CH_1) ? DAC_CHANNEL_1 : DAC_CHANNEL_2;
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       DAC通道初始化
 *
 * @param[in]   channel DAC通道(DAC_CH_1或DAC_CH_2)
 *
 * @retval      无
 *
 * @note        初始化指定DAC通道
 */
void dac_init(DAC_Channel_e channel)
{
    DAC_ChannelConfTypeDef dac_ch_conf = {0};

    /* 检查是否已初始化 */
    if (channel == DAC_CH_1 && sg_dac_ch1_initialized)
    {
        log_w("DAC通道1已经初始化");
        return;
    }

    if (channel == DAC_CH_2 && sg_dac_ch2_initialized)
    {
        log_w("DAC通道2已经初始化");
        return;
    }

    /* 使能DAC时钟 */
    DAC_DACx_CLK_ENABLE();

    /* 初始化GPIO */
    dac_gpio_init(channel);

    /* 配置DAC */
    sg_dac_handle.Instance = DAC_DACx;

    if (HAL_DAC_Init(&sg_dac_handle) != HAL_OK)
    {
        log_e("DAC外设初始化失败");
        return;
    }

    /* 配置DAC通道 */
    dac_ch_conf.DAC_Trigger = DAC_TRIGGER_NONE;             /* 软件触发 */
    dac_ch_conf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; /* 使能输出缓冲 */

    if (HAL_DAC_ConfigChannel(&sg_dac_handle, &dac_ch_conf, dac_get_hal_channel(channel)) != HAL_OK)
    {
        log_e("DAC通道配置失败");
        return;
    }

    /* 启动DAC */
    HAL_DAC_Start(&sg_dac_handle, dac_get_hal_channel(channel));

    /* 标记已初始化 */
    if (channel == DAC_CH_1)
    {
        sg_dac_ch1_initialized = 1;
        log_i("DAC通道1初始化完成 (PA4)");
    }
    else
    {
        sg_dac_ch2_initialized = 1;
        log_i("DAC通道2初始化完成 (PA5)");
    }
}

/**
 * @brief       DAC通道去初始化
 *
 * @param[in]   channel DAC通道
 *
 * @retval      无
 */
void dac_deinit(DAC_Channel_e channel)
{
    HAL_DAC_Stop(&sg_dac_handle, dac_get_hal_channel(channel));

    if (channel == DAC_CH_1)
    {
        sg_dac_ch1_initialized = 0;
        log_i("DAC通道1已关闭");
    }
    else
    {
        sg_dac_ch2_initialized = 0;
        log_i("DAC通道2已关闭");
    }
}

/**
 * @brief       设置DAC输出值
 *
 * @param[in]   channel DAC通道
 * @param[in]   value 输出值(0~4095)
 *
 * @retval      无
 *
 * @note        12位右对齐，范围0~4095对应0~3.3V
 */
void dac_set_value(DAC_Channel_e channel, uint16_t value)
{
    /* 限制范围 */
    if (value > DAC_MAX_VALUE_12BIT)
    {
        value = DAC_MAX_VALUE_12BIT;
    }

    /* 设置DAC输出 */
    HAL_DAC_SetValue(&sg_dac_handle, dac_get_hal_channel(channel), DAC_ALIGN_12B_R, value);
}

/**
 * @brief       设置DAC输出电压
 *
 * @param[in]   channel DAC通道
 * @param[in]   voltage_mv 输出电压(mV)，范围0~3300
 *
 * @retval      无
 *
 * @note        自动转换电压值为DAC数值
 */
void dac_set_voltage(DAC_Channel_e channel, uint16_t voltage_mv)
{
    uint16_t value;

    /* 限制范围 */
    if (voltage_mv > DAC_VREF_MV)
    {
        voltage_mv = DAC_VREF_MV;
    }

    /* 转换电压到DAC值 */
    value = (uint16_t)((uint32_t)voltage_mv * DAC_MAX_VALUE_12BIT / DAC_VREF_MV);

    /* 设置DAC输出 */
    dac_set_value(channel, value);

    log_d("DAC通道%d输出电压: %umV (DAC值=%u)", 
          (channel == DAC_CH_1) ? 1 : 2, voltage_mv, value);
}

/**
 * @brief       输出三角波
 *
 * @param[in]   channel DAC通道
 * @param[in]   amplitude 振幅(0~4095)
 *
 * @retval      无
 *
 * @note        使用DAC硬件三角波生成功能
 */
void dac_output_triangle_wave(DAC_Channel_e channel, uint16_t amplitude)
{
    DAC_ChannelConfTypeDef dac_ch_conf = {0};

    /* 限制振幅 */
    if (amplitude > DAC_MAX_VALUE_12BIT)
    {
        amplitude = DAC_MAX_VALUE_12BIT;
    }

    /* 配置三角波 */
    dac_ch_conf.DAC_Trigger = DAC_TRIGGER_T6_TRGO;          /* 定时器6触发 */
    dac_ch_conf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;

    HAL_DAC_ConfigChannel(&sg_dac_handle, &dac_ch_conf, dac_get_hal_channel(channel));

    /* 启动三角波生成 */
    HAL_DACEx_TriangleWaveGenerate(&sg_dac_handle, dac_get_hal_channel(channel), DAC_TRIANGLEAMPLITUDE_4095);
    HAL_DAC_Start(&sg_dac_handle, dac_get_hal_channel(channel));

    log_i("DAC通道%d输出三角波，振幅=%u", (channel == DAC_CH_1) ? 1 : 2, amplitude);
}

/**
 * @brief       输出噪声波
 *
 * @param[in]   channel DAC通道
 * @param[in]   amplitude 振幅(0~4095)
 *
 * @retval      无
 *
 * @note        使用DAC硬件噪声生成功能
 */
void dac_output_noise_wave(DAC_Channel_e channel, uint16_t amplitude)
{
    DAC_ChannelConfTypeDef dac_ch_conf = {0};

    /* 配置噪声波 */
    dac_ch_conf.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
    dac_ch_conf.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;

    HAL_DAC_ConfigChannel(&sg_dac_handle, &dac_ch_conf, dac_get_hal_channel(channel));

    /* 启动噪声生成 */
    HAL_DACEx_NoiseWaveGenerate(&sg_dac_handle, dac_get_hal_channel(channel), DAC_LFSRUNMASK_BITS11_0);
    HAL_DAC_Start(&sg_dac_handle, dac_get_hal_channel(channel));

    log_i("DAC通道%d输出噪声波，振幅=%u", (channel == DAC_CH_1) ? 1 : 2, amplitude);
}

/**
 * @brief       打印DAC状态（调试接口）
 *
 * @param       无
 *
 * @retval      无
 */
void dac_print_status(void)
{
    log_i("DAC CH1: %s", sg_dac_ch1_initialized ? "INITIALIZED" : "NOT INITIALIZED");
    log_i("DAC CH2: %s", sg_dac_ch2_initialized ? "INITIALIZED" : "NOT INITIALIZED");
}
